package com.tang.plugin.ui;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import com.tang.plugin.Config;
import com.tang.plugin.CreateModuleAction;
import com.tang.plugin.model.FileTreeNode;
import com.tang.plugin.model.Module;
import com.tang.plugin.utils.ActionToolbarUtils;
import com.tang.plugin.utils.PopMenuUtils;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;

public class RealConfigurePanel extends ConfigurePanel {

    private boolean modified = false;
    private Module currentConfig;
    private List<Module> configs;
    private PreviewPanel previewPanel;
    private EditableTable tablePlaceholder;
    private EditableTable tableFileTemp;
    private DefaultListModel<String> templateListModel;

    public RealConfigurePanel() {
        List<ActionToolbarUtils.Action> actionList = new ArrayList<>();
        ActionToolbarUtils.Action actionAdd = new ActionToolbarUtils.Action(AllIcons.General.Add, this::onAddConfig);
        ActionToolbarUtils.Action actionDelete = new ActionToolbarUtils.Action(AllIcons.General.Remove, this::onRemoveConfig);
        ActionToolbarUtils.Action actionCopy = new ActionToolbarUtils.Action(AllIcons.General.CopyHovered, this::onCopyConfig);
        ActionToolbarUtils.Action actionDownload = new ActionToolbarUtils.Action(AllIcons.Actions.Download, this::onExportTemplate);
        actionList.add(actionAdd);
        actionList.add(actionDelete);
        actionList.add(actionCopy);
        actionList.add(actionDownload);
        panelActionBar.add(ActionToolbarUtils.create("ActionBar1", actionList));
        initComponent();
        loadConfig();
        initData();
    }

    private void onExportTemplate() {
        FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
        descriptor.setTitle("Save Template to File");
        VirtualFile vf = FileChooser.chooseFile(descriptor, CreateModuleAction.pluginKit.getProject(), null);
        if (vf != null && vf.isWritable()) {
            String config = Config.GSON.toJson(currentConfig);
            File file = new File(vf.getPath(), currentConfig.getName() + ".json");
            OutputStreamWriter outputStream = null;
            try {
                outputStream = new OutputStreamWriter(new FileOutputStream(file));
                outputStream.write(config);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void onCopyConfig() {
        if (isNoConfigSelected()) {
            return;
        }

        Module newConfig = currentConfig.copyModule();
        newConfig.setName(newConfig.getName() + "_Copy");
        configs.add(newConfig);
        templateListModel.addElement(newConfig.getName());
        listTemplate.doLayout();
        listTemplate.setSelectedIndex(configs.indexOf(newConfig));
    }

    private void onRemoveConfig() {
        if (isNoConfigSelected()) {
            return;
        }
        int selectedIndex = getSelectedConfigIndex();
        configs.remove(selectedIndex);
        templateListModel.remove(selectedIndex);
        if (!listTemplate.isEmpty()) {
            previewPanel.setEnabled(true);
            listTemplate.setSelectedIndex(0);
            onConfigListSelected();
        } else {
            currentConfig = null;
            tablePlaceholder.setPairData(new HashMap<>());
            tableFileTemp.setPairData(new HashMap<>());
            previewPanel.setModuleConfig(Module.createEmpty());
            previewPanel.setEnabled(false);
        }
        listTemplate.doLayout();
    }

    private boolean isNoConfigSelected() {
        return getSelectedConfigIndex() == -1;
    }

    private void initData() {
        tableFileTemp.addChangeListener((e) -> modified = true);
        tablePlaceholder.addChangeListener((e) -> modified = true);
        previewPanel.setOnTreeUpdateListener(() -> modified = true);
        cbPlaceholder.addChangeListener((e) -> previewPanel.setReplacePlaceholder(cbPlaceholder.isSelected()));
        tabbedPane.addChangeListener((e) -> {
            if (currentConfig == null) {
                return;
            }
            int selectedIndex = tabbedPane.getSelectedIndex();
            switch (selectedIndex) {
                case 0:
                    currentConfig.getTemplate().setPlaceHolderMap(tablePlaceholder.getPairResult());
                    currentConfig.getTemplate().setFileTemplate(tableFileTemp.getPairResult());
                    break;
                case 1:
                    tableFileTemp.setPairData(currentConfig.getTemplate().getAllFileTemplateMap());
                    break;
                case 2:
                    tablePlaceholder.setPairData(currentConfig.getTemplate().getAllPlaceHolderMap());
                    break;
            }
            previewPanel.setModuleConfig(currentConfig);
        });
        listTemplate.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listTemplate.addListSelectionListener(e -> {
            if (isNoConfigSelected()) {
                return;
            }
            onConfigListSelected();
        });
        listTemplate.setModel(templateListModel);
        tfName.getDocument().addDocumentListener(new DocumentAdapter() {
            @Override
            protected void textChanged(@NotNull DocumentEvent documentEvent) {
                if (currentConfig != null) {
                    currentConfig.setName(tfName.getText());
                }
            }
        });
        if (templateListModel.size() > 1) {
            listTemplate.setSelectedIndex(0);
        }
    }

    private void loadConfig() {
        configs = Config.loadModuleTemplates();
        templateListModel = new DefaultListModel<>();
        configs.forEach((module) -> templateListModel.addElement(module.getName()));
        if (templateListModel.size() > 0) {
            listTemplate.setSelectedIndex(0);
        }
    }

    private void initComponent() {
        setLayout(new BorderLayout());
        add(contentPanel);
        previewPanel = new PreviewPanel();
        tablePlaceholder = new EditableTable(new String[]{"Placeholder", "Default Value"}, new boolean[]{true, true});
        tableFileTemp = new EditableTable(new String[]{"FileName", "Template"}, new boolean[]{true, true});
        panelStructure.add(previewPanel);
        panelPlaceholder.add(tablePlaceholder, BorderLayout.CENTER);
        panelFileTemp.add(tableFileTemp, BorderLayout.CENTER);
    }

    private void onAddConfig() {
        Map<String, PopMenuUtils.MenuCallback> map = new LinkedHashMap<>();
        map.put("Empty Template", () -> addModuleTemplate(Module.createEmpty()));
        map.put("* Import From File", () -> onImportTemplate());
        map.put("Route Module", () -> addModuleTemplate(Module.createRouteModule()));
        PopMenuUtils.create(map).show(panelActionBar, panelActionBar.getX(), panelActionBar.getY());
    }

    private void onImportTemplate() {
        FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor("json");
        descriptor.setTitle("Import Template From File");
        VirtualFile vf = FileChooser.chooseFile(descriptor, CreateModuleAction.pluginKit.getProject(), null);
        if (vf != null && vf.exists()) {
            File file = new File(vf.getPath());
            BufferedInputStream inputStream = null;
            try {
                inputStream = new BufferedInputStream(new FileInputStream(file));
                byte[] bytes = new byte[1024];
                int len = 0;
                StringBuilder stringBuilder = new StringBuilder();
                while ((len = inputStream.read(bytes)) > 0) {
                    stringBuilder.append(new String(bytes, 0, len));
                }
                Module template = Config.GSON.fromJson(stringBuilder.toString(), Module.class);
                template.initTemplate(template.getTemplate());
                addModuleTemplate(template);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void addModuleTemplate(Module module) {
        configs.forEach((it) -> {
            if (it.getName().equals(module.getName())) {
                module.setName(module.getName() + "_New");
            }
        });
        configs.add(module);
        templateListModel.addElement(module.getName());
        listTemplate.doLayout();
        listTemplate.setSelectedIndex(configs.indexOf(module));
        onConfigListSelected();
    }

    private void onConfigListSelected() {
        int index = getSelectedConfigIndex();
        if (currentConfig != null && currentConfig.equals(configs.get(index))) {
            return;
        }
        cacheConfig();
        currentConfig = configs.get(index);
        tfName.setText(currentConfig.getName());
        previewPanel.setModuleConfig(currentConfig);
        tableFileTemp.setPairData(currentConfig.getTemplate().getFileTemplate());
        tablePlaceholder.setPairData(currentConfig.getTemplate().getPlaceHolderMap());
    }

    private int getSelectedConfigIndex() {
        return listTemplate.getSelectedIndex();
    }

    public boolean isModified() {
        return modified;
    }

    public void cacheConfig() {
        if (currentConfig == null) {
            return;
        }
        FileTreeNode template = currentConfig.getTemplate();
        template.removeAllPlaceholderInTree();
        template.removeAllTemplateInTree();
        template.setFileTemplate(tableFileTemp.getPairResult());
        template.setPlaceHolderMap(tablePlaceholder.getPairResult());
    }

    public void saveConfig() {
        Config.saveModuleTemplates(configs);
        modified = false;
    }
}
